package web.controller.sys;

import framework.captcha.Captcha;
import framework.crypto.GeneralCrypto;
import framework.exceptions.Error401Exception;
import framework.security.AuthService;
import framework.security.password.PasswordService;
import framework.security.token.AuthTokenBuilder;
import framework.security.token.AuthTokenInfo;
import framework.storage.FileStorage;
import framework.utils.VersionUtil;
import framework.vo.ResultInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import system.service.sys.SysConfigService;
import system.vo.ConfigUI;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 匿名访问控制器
 * 可以放置一些允许匿名访问的控制器
 */
@Api(tags = "公众接口")
@RestController
@RequestMapping("/pub")
public class SysPubController {
    private static Instant UP_TIME;
    private static final int SALT_LENGTH = 19;
    @Autowired
    private PasswordService passwordService;
    @Autowired
    private SysConfigService configService;
    @Autowired
    private AuthService authService;
    @Autowired
    private Captcha captcha;
    @Autowired
    private AuthTokenBuilder tokenBuilder;
    @Autowired
    private GeneralCrypto generalCrypto;
    @Autowired
    private FileStorage fileStorage;

    public SysPubController() {
        UP_TIME = new Date().toInstant();
    }

//    @GetMapping("/404")
//    public void e404() throws Error404Exception {
//        ErrorUtil.notFound();
//    }
//
//    @GetMapping("/403")
//    public void e403() throws Error403Exception {
//        ErrorUtil.forbidden();
//    }
//
//    @GetMapping("/401")
//    public void e401() throws Error401Exception {
//        ErrorUtil.noAuthorization();
//    }
//
//    @GetMapping("/400")
//    public void e400() throws Error400Exception {
//        ErrorUtil.badRequest();
//    }
//
//    @GetMapping("/500")
//    public void e500() throws WebException {
//        ErrorUtil.serverError();
//    }
//
//    @GetMapping("/error")
//    public void error() throws BusinessException {
//        ErrorUtil.error("business error");
//    }


//    @ApiOperation("上传文件")
//    @PostMapping("/upload")
//    public String uploadFile(@RequestPart MultipartFile file) throws ServletException, IOException {
//        // 该接口为测试接口，因定上传文件地址
//        String id = "/test/test.bin";
//        this.fileStorage.save(file.getInputStream(), id);
//        return id;
//    }

//    @ApiOperation("下载文件")
//    @GetMapping("/download")
//    public void uploadFile(HttpServletResponse response) throws ServletException, IOException {
//        // 该接口为测试接口，因定上传文件地址
//        String id = "/test/test.bin";
//        try (InputStream inputStream = this.fileStorage.getStream(id)) {
//            try (ServletOutputStream outputStream = response.getOutputStream()) {
//                response.setHeader("Content-Disposition", "attachment; filename=\"test.bin\"");
//                IOUtils.copy(inputStream, outputStream);
//            }
//        }
//    }

    @PostMapping("/password")
    public Map password(String password, String salt) {
        return passwordDrive(password, salt);
    }

    @GetMapping("/password")
    public Map password() {
        String salt = RandomStringUtils.randomGraph(SALT_LENGTH);
        String password = RandomStringUtils.randomAlphanumeric(12);
        return passwordDrive(password, salt);
    }

    private Map passwordDrive(String password, String salt) {
        String encodePassword = this.passwordService.encode(password, salt);
        //
        Map map = new HashMap<String, Object>();
        map.put("salt", salt);
        map.put("password", password);
        map.put("encodePassword", encodePassword);
        if (this.generalCrypto.enable()) {
            map.put("passwordCipher", "gc");
            map.put("passwordValue", this.generalCrypto.encryptAsBase64(password));
        }
        return map;
    }

    /**
     * UI配置
     *
     * @throws IOException
     */
    @ApiOperation("UI配置")
    @GetMapping("/setting")
    public ResultInfo<ConfigUI> setting() throws IOException {
        ConfigUI ui = this.configService.getUI();
        return new ResultInfo<>(ui);
    }

    @GetMapping("/status")
    public Map status() {
        Instant instant = new Date().toInstant();
        SimpleDateFormat timeF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        //
        Map<String, Object> map = new HashMap<>();
        map.put("now_time", timeF.format(Date.from(instant)));
        map.put("up_time", timeF.format(Date.from(UP_TIME)));
        //
        SimpleDateFormat versionF = new SimpleDateFormat("yyyyMMddHHmmss");
        Date version = VersionUtil.jarVersion(this.getClass());
        map.put("version", versionF.format(version));
        map.put("ver_time", timeF.format(version));
        //
        Long accountId = this.authService.getAccountId();
        map.put("auth_userid", accountId == null ? 0 : accountId);
        map.put("auth_token", this.authService.getSecret());
        //
        return map;
    }

    /**
     * 验证码
     *
     * @param request
     * @param resp
     * @param id
     * @throws IOException
     */
    @ApiOperation("验证码")
    @GetMapping("/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse resp, @RequestParam String id) throws IOException {
        this.captcha.output(request, resp, id);
    }

    /**
     * 验证码验证
     *
     * @param code
     * @param id
     * @throws IOException
     */
    @ApiOperation("验证码验证")
    @PostMapping("/captcha/validate")
    public ResultInfo validate(@RequestParam String id, @RequestParam String code) throws IOException {
        boolean checked = this.captcha.check(id, code);
        ResultInfo r = new ResultInfo();
        if (!checked)
            r = r.failed("Failure");
        return r;
    }

    /**
     * token生成
     *
     * @param seconds
     * @throws IOException
     */
    @ApiOperation("token")
    @GetMapping("/token")
    public ResultInfo captcha(@RequestParam Integer seconds) throws IOException {
        Long accountId = this.authService.getAccountId();
        if (accountId == null || accountId == 0)
            throw new Error401Exception("No auth");
        AuthTokenInfo tokenInfo = new AuthTokenInfo(accountId, new Date(new Date().getTime() + seconds * 1000));
        String token = this.tokenBuilder.encode(tokenInfo);
        return new ResultInfo(token);
    }

    /**
     * 获取一般性加密公钥
     */
    @ApiOperation("获取一般性加密公钥")
    @GetMapping("/publicKey")
    public ResultInfo<String> publicKey(HttpServletResponse response) throws IOException {
        return new ResultInfo<>(this.generalCrypto.getPublicKeyContent());
    }

    /**
     * 获取一般性加密公钥
     */
    @ApiOperation("获取一般性加密公钥")
    @GetMapping("/publicKey.js")
    public String publicKeyJs(HttpServletResponse response, Integer includeHead) throws IOException {
        response.setContentType("application/javascript");
        String publicKeyContent = this.generalCrypto.getPublicKeyContent();
        publicKeyContent = publicKeyContent.replace("\r\n", "");
        if (includeHead != null && includeHead == 0) {
            publicKeyContent = publicKeyContent.replace("-----BEGIN PUBLIC KEY-----", "");
            publicKeyContent = publicKeyContent.replace("-----END PUBLIC KEY-----", "");
        }
        return "var publicKey=\"" + publicKeyContent + "\";";
    }

}
